cmake_minimum_required(VERSION 3.2)
project(tbir CXX)

SET(CMAKE_LOCAL "${PROJECT_SOURCE_DIR}/cmake")
LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_LOCAL}/)
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/recipes)
        SET(CMAKE_INSTALL_RPATH ".")
list(APPEND CMAKE_PREFIX_PATH $ENV{CONDA_PREFIX})

IF (DEFINED ENV{CUDA_HOME})
    MESSAGE(STATUS "USE CUDA CUDA_HOME: $ENV{CUDA_HOME}")
    SET(USE_CUDA $ENV{CUDA_HOME})
ENDIF ()

IF (USE_CUDA)
    INCLUDE(cmake/FindCUDA.cmake)
    find_cuda(${USE_CUDA})
    INCLUDE_DIRECTORIES(SYSTEM ${CUDA_INCLUDE_DIRS})
    SET(CMAKE_CUDA_FLAGS "-O2 -Xcompiler=-Wall -Xcompiler=-fPIC ${CMAKE_CUDA_FLAGS}")
    MESSAGE(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}")
ENDIF ()

IF (ENABLE_RUNTIME_STRING_INVARIANT_CHECK)
    ADD_DEFINITIONS(-DTBIR_RUNTIME_STRING_UNICODE_ENABLE_INVARIANT_CHECK)
ENDIF ()

IF (BUILD_MICRO_RUNTIME)
    ADD_DEFINITIONS(-DTBIR_BUILD_MICRO_RUNTIME)
    ADD_DEFINITIONS(-DTBIR_SUPPORT_ANDROID)
    ADD_DEFINITIONS(-DDISABLE_UNICODEDATA)
ELSE ()
    ADD_DEFINITIONS(-DTBIR_RUNTIME_ENABLE_STRINGREF)
    # third-part
    FIND_PACKAGE(PCRE REQUIRED)
    INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIR})
    # jemalloc
    FIND_PACKAGE(Jemalloc)
    IF (JEMALLOC_INCLUDE_DIR)
        INCLUDE_DIRECTORIES(${JEMALLOC_INCLUDE_DIR})
        ADD_DEFINITIONS(-DUSE_JEMALLOC)
    ENDIF ()
ENDIF ()

IF (PCRE_FOUND)
    ADD_DEFINITIONS(-DTBIR_ENABLE_PCRE_REGEX)
ENDIF ()

INCLUDE_DIRECTORIES(include)
INCLUDE_DIRECTORIES($ENV{CONDA_PREFIX}/include)
INCLUDE_DIRECTORIES(3rdparty/alloc/include/brt)

IF (DEFINED ENV{CFLAGS})
    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{CFLAGS}")
ENDIF ()
IF (DEFINED ENV{CXXFLAGS})
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{CXXFLAGS}")
ENDIF ()
IF (DEFINED ENV{CPPFLAGS})
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{CPPFLAGS}")
ENDIF ()
IF (NOT CMAKE_BUILD_TYPE)
    MESSAGE(STATUS "No build type selected, default to ReleaseWithDebugInfo")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O2 -DNDEBUG")
ENDIF ()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fPIC -ftls-model=global-dynamic")
MESSAGE(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

# cuda src
FILE(GLOB_RECURSE TBIR_CUDA_SRCS RELATIVE ${CMAKE_SOURCE_DIR} "src/runtime/cuda/*.cc" "src/runtime/cuda/*.cpp" "src/runtime/cuda/*.h")
# allocator
FILE(GLOB_RECURSE MEM_ALLOC RELATIVE ${CMAKE_SOURCE_DIR} "3rdparty/alloc/*.cc")
FILE(GLOB_RECURSE MEM_CUDA_ALLOC RELATIVE ${CMAKE_SOURCE_DIR} "3rdparty/alloc/brt/core/device/cuda/*.cc")
# regex src
FILE(GLOB_RECURSE TBIR_REGEX_HS RELATIVE ${CMAKE_SOURCE_DIR} "include/tbir/runtime/regex/*.h")
FILE(GLOB_RECURSE TBIR_REGEX_SRCS RELATIVE ${CMAKE_SOURCE_DIR} "src/runtime/regex/*.cc" "src/runtime/regex/*.cpp")
# runtime src
FILE(GLOB_RECURSE TBIR_RUNTIME_HS RELATIVE ${CMAKE_SOURCE_DIR} "include/tbir/runtime/*.h")
FILE(GLOB_RECURSE TBIR_RUNTIME_SRCS RELATIVE ${CMAKE_SOURCE_DIR} "src/runtime/*.cc" "src/runtime/*.cpp" "src/runtime/*.h")
# pipeline src
FILE(GLOB_RECURSE TBIR_PIPELINE_HS RELATIVE ${CMAKE_SOURCE_DIR} "include/tbir/pipeline/*.h")
FILE(GLOB_RECURSE TBIR_PIPELINE_SRCS RELATIVE ${CMAKE_SOURCE_DIR} "src/pipeline/*.cc" "src/pipeline/*.cpp" "src/pipeline/*.h")
# unicodedata src
FILE(GLOB_RECURSE TBIR_UNICODEDATA_HS RELATIVE ${CMAKE_SOURCE_DIR} "include/tbir/runtime/unicodelib/py_unicodedata.h")
FILE(GLOB_RECURSE TBIR_UNICODEDATA_SRCS RELATIVE ${CMAKE_SOURCE_DIR} "src/runtime/unicodelib/py_unicodedata.cc")
# other src
FILE(GLOB_RECURSE TBIR_OTHER_HS RELATIVE ${CMAKE_SOURCE_DIR} "include/tbir/ir/*.h" "include/tbir/server/*.h")
FILE(GLOB_RECURSE
        TBIR_OTHER_SRCS
        RELATIVE
        ${CMAKE_SOURCE_DIR}
        "src/codegen/*.cc" "src/codegen/*.cpp" "src/codegen/*.h"
        "src/ir/*.cc" "src/ir/*.cpp" "src/ir/*.h"
        "src/printer/*.cc" "src/printer/*.cpp" "src/printer/*.h"
        "src/server/*.cc" "src/server/*.cpp" "src/server/*.h"
        "src/c_api/*.cc" "src/c_api/*.cpp" "src/c_api/*.h")

IF (BUILD_MICRO_RUNTIME)
    # generic src
    SET(TBIR_HS ${TBIR_RUNTIME_HS} ${TBIR_PIPELINE_HS})
    SET(TBIR_SRCS ${TBIR_RUNTIME_SRCS} ${TBIR_PIPELINE_SRCS})
    LIST(REMOVE_ITEM TBIR_HS ${TBIR_UNICODEDATA_HS})
    LIST(REMOVE_ITEM TBIR_SRCS ${TBIR_UNICODEDATA_SRCS})
ELSE ()
    # generic src
    SET(TBIR_HS ${TBIR_RUNTIME_HS} ${TBIR_PIPELINE_HS} ${TBIR_OTHER_HS})
    SET(TBIR_SRCS ${TBIR_RUNTIME_SRCS} ${TBIR_PIPELINE_SRCS} ${TBIR_OTHER_SRCS})
ENDIF ()

IF (NOT PCRE_FOUND)
    LIST(REMOVE_ITEM TBIR_HS ${TBIR_REGEX_HS})
    LIST(REMOVE_ITEM TBIR_SRCS ${TBIR_REGEX_SRCS})
ENDIF ()

LIST(REMOVE_ITEM TBIR_SRCS ${TBIR_CUDA_SRCS})
LIST(REMOVE_ITEM MEM_ALLOC ${MEM_CUDA_ALLOC})

include(require_turbo)

ADD_LIBRARY(tbir SHARED ${TBIR_HS} ${TBIR_SRCS} ${MEM_ALLOC})

IF (BUILD_MICRO_RUNTIME)
    SET_TARGET_PROPERTIES(tbir PROPERTIES LINK_FLAGS_RELEASE -s)
ELSE ()
    TARGET_LINK_LIBRARIES(tbir pthread)
ENDIF ()
TARGET_LINK_LIBRARIES(tbir dl ${TURBO_LIB})
IF (PCRE_FOUND)
    TARGET_LINK_LIBRARIES(tbir ${PCRE_LIBRARIES})
ENDIF ()

IF (USE_CUDA)
    ADD_LIBRARY(tbir_cuda SHARED ${TBIR_CUDA_SRCS} ${MEM_CUDA_ALLOC})
    TARGET_LINK_LIBRARIES(tbir_cuda tbir)
    # TARGET_LINK_LIBRARIES(tbir_cuda ${CUDA_NVRTC_LIBRARY})
    TARGET_LINK_LIBRARIES(tbir_cuda ${CUDA_CUDA_LIBRARY})
    TARGET_LINK_LIBRARIES(tbir_cuda ${CUDA_CUDART_LIBRARY})
ENDIF ()

IF (JEMALLOC_LIBRARIES)
    TARGET_LINK_LIBRARIES(tbir ${JEMALLOC_LIBRARIES})
ENDIF ()


SET(USE_LIBBACKTRACE OFF)
IF (DEFINED ENV{USE_LIBBACKTRACE})
    MESSAGE(STATUS "USE LIB_BACKTRACE: $ENV{USE_LIBBACKTRACE}")
    IF (CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "Linux")
        SET(USE_LIBBACKTRACE $ENV{USE_LIBBACKTRACE})
    ENDIF ()
ENDIF ()

#IF (USE_LIBBACKTRACE)
#    MESSAGE("Building with libbacktrace...")
#    include(cmake/Libbacktrace.cmake)
#    TARGET_LINK_LIBRARIES(tbir libbacktrace)
#    target_include_directories(tbir PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace/include)
#    target_compile_definitions(tbir PUBLIC TBIR_WITH_LIBBACKTRACE)
#ENDIF ()

option(BUILD_TESTING "enable cc testing" ON)

IF (BUILD_TESTING)
    ENABLE_TESTING()
    MESSAGE(STATUS "BUILD_TESTING: ON")
    ADD_SUBDIRECTORY(test/cc/)
ENDIF ()

OPTION(BUILD_BENCHMARK OFF)


IF (BUILD_MICRO_RUNTIME)
    INSTALL(DIRECTORY include/tbir DESTINATION include)
    INSTALL(TARGETS tbir
            RUNTIME DESTINATION bin
            LIBRARY DESTINATION lib
            ARCHIVE DESTINATION lib)
ELSE ()
    INSTALL(DIRECTORY include/tbir DESTINATION include)

    IF (USE_CUDA)
        SET(targets tbir tbir_cuda)
    ELSE ()
        SET(targets tbir)
    ENDIF ()

    INSTALL(TARGETS ${targets}
            RUNTIME DESTINATION bin
            LIBRARY DESTINATION lib
            ARCHIVE DESTINATION lib)
ENDIF ()
